package com.haodai.vip.tomcat.server;

import com.haodai.vip.tomcat.utils.DateUtils;
import com.haodai.vip.tomcat.utils.LogUtils;

import java.io.*;
import java.net.Socket;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.zip.CRC32;

/**
 * Created by huangtao on 17/6/1.
 */
public class ServerThread extends Thread {

    private HttpServer httpServer;
    private Socket socket;

    public ServerThread(HttpServer httpServer, Socket socket){
        this.httpServer = httpServer;
        this.socket = socket;
    }

    @Override
    public void run() {
        try {
            InputStream input = socket.getInputStream();
            OutputStream output = socket.getOutputStream();
            boolean isHandlerRequest = false;

            Request request = new Request(input, output);
            request.setHost(socket.getInetAddress().getHostAddress());
            Response response = new Response(output);

            String requestPath = request.getPath();
            if (requestPath == null){
                String errorMessage = "HTTP/1.1 500 error\r\n" +
                        "Content-Type: text/html\r\n" +
                        "Content-Type: text/html;charset="+Config.Encoding.ENCODE+"\r\n" +
                        "\r\n<h1>server error<br/>没有获取到传递来的内容</h1>";
                output.write(errorMessage.getBytes());
                isHandlerRequest = true;
            } else {
                if (requestPath.endsWith(Config.Controller.ACTION_SUFFIX)){ //动态资源
                    for (Map.Entry<String, Servlet> entry : httpServer.getControllerMap().entrySet()){
                        if (requestPath.equals("/"+entry.getKey())){
                            Servlet controller = entry.getValue();
                            try {
                                if (Config.Method.GET.equalsIgnoreCase(request.getMethod())){
                                    controller.get(request, response);
                                } else {
                                    controller.post(request, response);
                                }
                                String acceptEncoding = request.getHeader("Accept-Encoding");
                                if (acceptEncoding != null && (acceptEncoding.contains("gzip") || acceptEncoding.contains("GZIP"))){
                                    LogUtils.info("GZIP压缩");
                                    response.gzip();
                                } else {
                                    LogUtils.info("不GZIP压缩");
                                    response.out();
                                }
                            } catch (Exception e){
                                e.printStackTrace();
                                String errorMessage = "HTTP/1.1 500 error\r\n" +
                                        "Content-Type: text/html\r\n" +
                                        "Content-Type: text/html;charset="+Config.Encoding.ENCODE+"\r\n" +
                                        "\r\n<h1>server error<br/>"+e.getMessage()+"</h1>";
                                output.write(errorMessage.getBytes());
                            }

                            isHandlerRequest = true;
                        }
                    }
                } else {  //静态资源
                    FileInputStream fis = null;
                    ByteArrayOutputStream bos = null;
                    try {
                        File file = new File(System.getProperty("user.dir")+File.separator+Config.Server.WEB_ROOT, requestPath);
                        byte[] buffer = new byte[Config.IO.BUFFER_SIZE];
                        if (file.exists()) {
                            fis = new FileInputStream(file);
                            if (requestPath.endsWith(Config.Controller.STATIC_TXT_1_SUFFIX) || requestPath.endsWith(Config.Controller.STATIC_TXT_2_SUFFIX)) {
                                bos = new ByteArrayOutputStream();
                                int len;
                                while ((len = fis.read(buffer)) != -1) {
                                    bos.write(buffer, 0, len);
                                }
                                byte[] bytes = bos.toByteArray();

                                //ETag
                                CRC32 crc = new CRC32();
                                crc.update(bytes);
                                String token = crc.getValue()+"";
                                String preToken = request.getHeader("If-None-Match");
                                if (preToken != null && token.equalsIgnoreCase(preToken)){
                                    String content = new String(bytes, Config.Encoding.ENCODE);
                                    String errorMessage = "HTTP/1.1 304 Not Modified\r\n" +
                                            "Content-Type: text/html;charset="+Config.Encoding.ENCODE+"\r\n" +
                                            "Content-Length: "+bytes.length+"\r\n" +
                                            "ETag: "+token+"\r\n" +
                                            "Last-Modified: "+ request.getHeader("If-Modified-Since")+"\r\n" +
                                            "\r\n" +content;
                                    output.write(errorMessage.getBytes(Config.Encoding.ENCODE));
                                } else {
                                    String content = new String(bytes, Config.Encoding.ENCODE);
                                    String errorMessage = "HTTP/1.1 200 ok\r\n" +
                                            "Content-Type: text/html;charset="+Config.Encoding.ENCODE+"\r\n" +
                                            "Content-Length: "+bytes.length+"\r\n" +
                                            "ETag: "+token+"\r\n" +
                                            "Last-Modified: "+ DateUtils.getGMT(new Date().getTime(), 0)+"\r\n" +
                                            "\r\n" +content;
                                    output.write(errorMessage.getBytes(Config.Encoding.ENCODE));
                                }
                            } else {
                                if (requestPath.endsWith("hello_java.pl")){
                                    try {
                                        String[] cmd = {"/bin/sh","-c",file.getAbsolutePath()+" "+request.getParam("name")+" "+request.getParam("pwd")};
                                        Process ps = Runtime.getRuntime().exec(cmd);
                                        ps.waitFor();
                                        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                                        byte[] bBuf = new byte[2048];
                                        InputStream cgiOutput = ps.getInputStream();
                                        int bufRead = -1;
                                        while ((bufRead = cgiOutput.read(bBuf)) != -1) {
                                            byteArrayOutputStream.write(bBuf, 0, bufRead);
                                        }
                                        ps.exitValue();
                                        String content = byteArrayOutputStream.toString(Config.Encoding.ENCODE);
                                        byte[] contentBytes = content.getBytes(Config.Encoding.ENCODE);
                                        String responseMessage = "HTTP/1.1 200 ok\r\n";
                                        responseMessage+="Content-Length: "+contentBytes.length+"\r\n";
                                        responseMessage += "\r\n" +content;
                                        output.write(responseMessage.getBytes(Config.Encoding.ENCODE));
                                    }
                                    catch (Exception e) {
                                        e.printStackTrace();
                                    }

                                } else {
                                    //图片和其他下载资源
                                    String[] resourceSplit = requestPath.split("\\.");
                                    StringBuilder sb = new StringBuilder("HTTP/1.1 200 ok\r\n");
                                    sb.append("Content-Length: "+file.length()+"\r\n");
                                    sb.append("Accept-Ranges: bytes\r\n");

                                    String resourceSuffix = resourceSplit[1];
                                    if ("png".equals(resourceSuffix) || "jpg".equals(resourceSuffix) || "jpeg".equals(resourceSuffix)){
                                        sb.append("Content-Type: image/"+resourceSuffix+"\r\n\r\n");
                                    } else {
                                        sb.append("Content-Type: application/octet-stream\r\n\r\n");
                                    }

                                    output.write(sb.toString().getBytes(Config.Encoding.ENCODE));

                                    //写内容
                                    int len;
                                    while ((len = fis.read(buffer)) != -1){
                                        output.write(buffer, 0, len);
                                    }
                                }
                            }

                            isHandlerRequest = true;
                        }

                    } finally {
                        if (fis != null){
                            fis.close();
                        }
                    }
                }
            }


            if (!isHandlerRequest){
                String errorMessage = "HTTP/1.1 404 File Not Found\r\n" +
                        "Content-Type: text/html\r\n" +
                        "Content-Type: text/html;charset="+Config.Encoding.ENCODE+"\r\n" +
                        "\r\n<h1>File Not Found</h1>";
                output.write(errorMessage.getBytes());
            }
            socket.close();
        } catch (Exception e){
            e.printStackTrace();
        }
    }
}
